/*
 * File:    SoapQuery.java
 * Created: 25-Jun-2007
 * Version: $Id$
 *
 * COPYRIGHT (C) 2007, Bitgate Software, LLC.  All Rights Reserved.
 *
 * software@bitgatesoftware.com
 */

package com.bitgate.util.soap;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import static com.bitgate.util.debug.Debug.*;

/**
 * This is a helper class that is used to perform specific SOAP-related functions on a SOAP request, or to prepare a SOAP request.
 * 
 * @author khollis
 */
public class SoapQuery
{
	/**
	 * This takes the contents of a class that uses the <code>Soap</code> annotation, and walks through it to find the names
	 * of the publishable items.  These items are returned as a list of <code>String</code> objects.
	 * 
	 * @param soapClass The <code>Soap</code> annotated class.
	 * @return <code>List&lt;String&gt;</code> containing the methods to publish.
	 * @throws SoapException on any errors.
	 */
	public List<String> getPublishedObjects(Class<?> soapClass) throws SoapException
	{
		ArrayList<String> published = new ArrayList<String>();
		
		if (soapClass.isAnnotationPresent(Soap.class)) {
			Soap annotationData = soapClass.getAnnotation(Soap.class);
			
			if (isDebugEnabled()) {
				debug("Class '" + soapClass.getClass().getName() + "' soap annotated: requireSession='" +
					annotationData.requireSession() + "' entryPoint='" + annotationData.entryPoint() + "'");
			}
			
			Method[] methods = soapClass.getMethods();
			
			for(Method method : methods) {
				if (method.isAnnotationPresent(Publishable.class)) {
					published.add(method.getName());
				}
			}
		} else {
			throw new SoapException("Class '" + soapClass.getClass().getName() + "' is not annotated by the Soap annotation.");
		}
		
		if (published.size() == 0) {
			warning("Soap-annotized class '" + soapClass.getClass().getName() + "' does not publish any valid members.");
		}
		
		return published;
	}
	
	/**
	 * Returns the entry point for the specified SOAP class, by directory name.
	 * 
	 * @param soapClass <code>Class&lt;?&gt;</code> to look up.
	 * @return <code>String</code> containing the entry point.
	 * @throws SoapException on any errors.
	 */
	public String getEntryPoint(Class<?> soapClass) throws SoapException
	{
		if (soapClass.isAnnotationPresent(Soap.class)) {
			Soap annotationData = soapClass.getAnnotation(Soap.class);
			
			return annotationData.entryPoint();
		}
		
		throw new SoapException("Class '" + soapClass.getClass().getName() + "' is not annotated by the Soap annotation.");
	}
	
	/**
	 * Returns a boolean indicating if an active session is required to call this SOAP method or class.
	 * 
	 * @param soapClass <code>Class&lt;?&gt;</code> to look up.
	 * @return <code>true</code> if a session is required, <code>false</code> otherwise.
	 * @throws SoapException on any errors.
	 */
	public boolean getRequireSession(Class<?> soapClass) throws SoapException
	{
		if (soapClass.isAnnotationPresent(Soap.class)) {
			Soap annotationData = soapClass.getAnnotation(Soap.class);
			
			return annotationData.requireSession();
		}
		
		throw new SoapException("Class '" + soapClass.getClass().getName() + "' is not annotated by the Soap annotation.");
	}
	
	/**
	 * Returns overall class documentation for the service class, not the methods inside.
	 * 
	 * @param soapClass <code>Class&lt;?&gt;</code> to look up.
	 * @return <code>String</code> containing the documentation for the SOAP service.
	 * @throws SoapException on any errors.
	 */
	public String getDocumentation(Class<?> soapClass) throws SoapException
	{
		if (soapClass.isAnnotationPresent(Soap.class)) {
			Soap annotationData = soapClass.getAnnotation(Soap.class);
			
			return annotationData.documentation();
		}
		
		throw new SoapException("Class '" + soapClass.getClass().getName() + "' is not annotated by the Soap annotation.");
	}
	
	/**
	 * Returns SOAP documentation for the method name specified.
	 * 
	 * @param soapClass <code>Class&lt;?&gt;</code> to look up.
	 * @param methodName <code>String</code> containing the method to look up.
	 * @return <code>String</code> containing the relevant documentation for the method.
	 * @throws SoapException on any errors.
	 */
	public String getMethodDocumentation(Class<?> soapClass, String methodName) throws SoapException
	{
		if (soapClass.isAnnotationPresent(Soap.class)) {
			Method methods[] = soapClass.getDeclaredMethods();
			
			for(Method method : methods) {
				if (method.getName().equals(methodName)) {
					if (method.isAnnotationPresent(Publishable.class)) {
						Publishable publishableData = method.getAnnotation(Publishable.class);
						
						return publishableData.documentation();
					}
				}
			}

			throw new SoapException("Method '" + methodName + "' is not annotated by the Publishable annotation.");
		}
		
		throw new SoapException("Class '" + soapClass.getClass().getName() + "' is not annotated by the Soap annotation.");
	}
}